/*
 * Copyright 2010-2011 CGT&DC ISA RAS
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package websolve.workflow.wfms;

import java.io.File;
import java.util.Map.Entry;
import java.util.logging.Logger;

import javax.servlet.ServletContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.HttpMethod;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.SecurityContext;
import javax.ws.rs.core.UriInfo;

import org.codehaus.jettison.json.JSONArray;
import org.codehaus.jettison.json.JSONException;
import org.codehaus.jettison.json.JSONObject;

import websolve.workflow.runtime.Workflow;
import websolve.workflow.wfms.security.AuthzContext;
import websolve.workflow.wfms.security.AuthzManager;

import com.sun.jersey.api.NotFoundException;
import com.sun.jersey.spi.resource.Singleton;

@Singleton
@Path("/")
public class WorkflowsResource {

    @Context
    private ServletContext ctx;
    @Context
    private UriInfo uriInfo;
    @Context
    private SecurityContext securityCtx;

    @GET
    @Produces("application/json")
    public JSONArray getWorkflowsJSON() throws JSONException {
        AuthzManager.getInstance(ctx).authorize(
                new AuthzContext(securityCtx, AuthzContext.WORKFLOWS_RESOURCE, null, HttpMethod.GET));
        log.fine("GET (JSON) - get workflow list");

        JSONArray response = new JSONArray();

        for (Entry<String, WorkflowEntry> e : WorkflowManager.getInstance(ctx).getWorkflows().entrySet()) {
            String workflowId = e.getKey();
            WorkflowEntry wf = e.getValue();
            JSONObject json = wf.getDescription();
            JSONObject properties = json.getJSONObject("working").getJSONObject("properties");

            JSONObject info = new JSONObject();
            info.put("file", workflowId);
            info.put("name", properties.get("name"));
            info.put("description", properties.get("description"));
            response.put(info);
        }
        log.finer("GET (JSON) response: " + response);
        return response;
    }

    @POST
    @Consumes("application/json")
    public Response addWorkflow(JSONObject request) throws Exception {
        AuthzManager.getInstance(ctx).authorize(
                new AuthzContext(securityCtx, AuthzContext.WORKFLOWS_RESOURCE, null, HttpMethod.POST));
        log.fine("POST (JSON) - create new workflow");
        log.finer("POST (JSON) request: " + request);

        String owner;
        if (securityCtx.isSecure()) {
            owner = securityCtx.getUserPrincipal().getName();
        } else {
            owner = null;
        }
        String workflowId = WorkflowManager.getInstance(ctx).addWorkflow(request.toString(), owner);

        log.finer("POST (JSON) response: " + workflowId);
        return Response.ok(workflowId).build();
    }

    @Path("{workflowId}")
    public WorkflowResource getWorkflowResource(@PathParam("workflowId") String workflowId) {
        WorkflowManager wfMan = WorkflowManager.getInstance(ctx);
        if (wfMan.hasWorkflow(workflowId)) {
            return new WorkflowResource(workflowId, ctx, securityCtx);
        } else {
            throw new NotFoundException("Workflow " + workflowId + " not found");
        }
    }

    @Path("instances")
    @GET
    @Produces("text/html")
    public Response listInstancesHTML() {
        AuthzManager.getInstance(ctx).authorize(
                new AuthzContext(securityCtx, AuthzContext.INSTANCES_RESOURCE, null, HttpMethod.GET));
        log.fine("GET instances (HTML)");
        String response = "";
        for (Entry<String, WorkflowEntry> e : WorkflowManager.getInstance(ctx).getWorkflows().entrySet()) {
            for (Entry<String, Workflow> i : e.getValue().getInstances().entrySet()) {
                Workflow wi = i.getValue();
                response += wi.getStartTime() + " - " + (wi.getFinishTime() != null ? wi.getFinishTime() : "...")
                        + " <a href=\"/services/" + e.getKey() + "/job" + i.getKey() + "\">" + wi.getName() + "</a> "
                        + wi.getState() + "<br/>";
            }
        }
        return Response.ok(response).build();
    }

    @Path("instances")
    @GET
    @Produces("application/json")
    public JSONArray listInstancesJSON() throws JSONException {
        AuthzManager.getInstance(ctx).authorize(
                new AuthzContext(securityCtx, AuthzContext.INSTANCES_RESOURCE, null, HttpMethod.GET));
        log.fine("GET instances (JSON)");
        JSONArray response = new JSONArray();
        for (Entry<String, WorkflowEntry> e : WorkflowManager.getInstance(ctx).getWorkflows().entrySet()) {
            String workflowId = e.getKey();
            for (Entry<String, Workflow> i : e.getValue().getInstances().entrySet()) {
                String instanceId = i.getKey();
                Workflow instance = i.getValue();
                JSONObject instanceJSON = new JSONObject();
                instanceJSON.put("uri", "http://" + uriInfo.getBaseUri().getHost() + ":"
                        + uriInfo.getBaseUri().getPort() + "/services/" + workflowId + "/job" + instanceId);
                instanceJSON.put("name", instance.getName());
                instanceJSON.put("state", instance.getState());
                instanceJSON.put("start-time", instance.getStartTime());
                instanceJSON.put("finish-time", instance.getFinishTime());
                response.put(instanceJSON);
            }
        }
        log.finer("GET instances (JSON) response: " + response);
        return response;
    }

    @Path("log")
    @GET
    @Produces("text/html")
    public Response listLogFiles() {
        log.fine("GET log (HTML)");
        String response = "";
        File logDir = new File("log");
        for (File file : logDir.listFiles()) {
            response += "<a href=\"http://" + uriInfo.getBaseUri().getHost() + ":" + uriInfo.getBaseUri().getPort()
                    + "/log/" + file.getName() + "\">" + file.getName() + "</a><br />";
        }
        return Response.ok(response).build();
    }

    private static final Logger log = Logger.getLogger(WorkflowsResource.class.getName());
}
